﻿using System.Runtime.InteropServices;
using Win32Proxy.Api;
using Win32Proxy.Enums;
using Win32Proxy.Helper;
using Win32Proxy.Structs;

namespace WinCapturer
{
    public sealed class CaptureHelper
    {
        public event Action<string, IntPtr, Win32Proxy.Structs.BitmapInfo> CaptureDone =
            (captureName, bitmapPtr, bitmapInfo) => { };

        public int Fps { get; set; } = 15;

        private double TimerInterval => 1000.0 / Fps;
#pragma warning disable CS8618 // 在退出构造函数时，不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。
        private string _captureName;
        private System.Threading.Timer _timer;
#pragma warning restore CS8618 // 在退出构造函数时，不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。


        public bool Start(string captureName, IntPtr handle, CaptureType type = CaptureType.CreateDibSection)
        {
            if (!CaptureService.Instance.RegisterCapture(captureName, handle, type))
            {
                return false;
            }

            _captureName = captureName;

            //创建守护定时器，马上执行
#pragma warning disable CS8622 // 参数类型中引用类型的为 Null 性与目标委托不匹配(可能是由于为 Null 性特性)。
            _timer = new System.Threading.Timer(CaptureFunc, null,
                TimeSpan.FromMilliseconds(0), Timeout.InfiniteTimeSpan);
#pragma warning restore CS8622 // 参数类型中引用类型的为 Null 性与目标委托不匹配(可能是由于为 Null 性特性)。

            return true;
        }

        public void Stop()
        {
            //移除定时器
            _timer?.Dispose();
#pragma warning disable CS8625 // 无法将 null 字面量转换为非 null 的引用类型。
            _timer = null;
#pragma warning restore CS8625 // 无法将 null 字面量转换为非 null 的引用类型。

            CaptureService.Instance.UnRegisterCapture(_captureName);
            _captureName = string.Empty;
        }

        private void CaptureFunc(object state)
        {
            Capture();

            //执行下次定时器
            _timer?.Change(TimeSpan.FromMilliseconds(TimerInterval), Timeout.InfiniteTimeSpan);
        }

        private void Capture()
        {
            IntPtr bitsPtr;
            if (!CaptureService.Instance.Capture(_captureName, out bitsPtr))
            {
                return;
            }

            var bitmapPtr = CaptureService.Instance.GetBitmapPtr(_captureName);
            var bitmapInfo = CaptureService.Instance.GetBitmapInfo(_captureName);
            CaptureDone.Invoke(_captureName, bitmapPtr, bitmapInfo);
        }

        /// <summary>
        /// 窗口截图
        /// </summary>
        /// <param name="windownHandle"></param>
        /// <returns></returns>
        public static System.Drawing.Bitmap? GetWindowCapture(IntPtr windownHandle)
        {
            PrintCaptureHelper capture = new PrintCaptureHelper();
            capture.Init(windownHandle);
            var image = System.Drawing.Image.FromHbitmap(capture.Capture());
            capture.Cleanup();
            GC.Collect();
            return image;


            //System.Drawing.Rectangle rect = WindowHelper.GetWindowBounds(windownHandle);

            //if(rect == System.Drawing.Rectangle.Empty) return null;

            //IntPtr scrDc = User32.GetWindowDC(windownHandle);
            //IntPtr hBitmap = GDI32.CreateCompatibleBitmap(scrDc, rect.Width, rect.Height);
            //IntPtr memDc = GDI32.CreateCompatibleDC(scrDc);
            //IntPtr oldBmp = GDI32.SelectObject(memDc, hBitmap);

            //var ret = User32.PrintWindow(windownHandle, memDc, 1 | 2);
            //using System.Drawing.Bitmap bmp = System.Drawing.Bitmap.FromHbitmap(hBitmap);
            //GDI32.DeleteObject(hBitmap);
            //GDI32.DeleteDC(memDc);
            //User32.ReleaseDC(windownHandle, scrDc);
            //return ret ? bmp.Clone() as System.Drawing.Bitmap : null;
        }

        /// <summary>
        /// 桌面截图
        /// </summary>
        /// <param name="screen"></param>
        /// <returns></returns>
        public static System.Drawing.Bitmap? GetDesktopCapture(Screen screen)
        {
            System.Drawing.Rectangle rect = MonitorHelper.GetScreenResolution(screen.DeviceName);
            //Rectangle rect = new(screen.Bounds.Location.X, screen.Bounds.Location.Y, screen.Bounds.Width, screen.Bounds.Height);
            using System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(rect.Width, rect.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            using Graphics g = Graphics.FromImage(bmp);
            IntPtr gHdc = g.GetHdc();
            IntPtr deskHandle = User32.GetDesktopWindow();
            IntPtr dHdc = User32.GetDC(deskHandle);
            GDI32.BitBlt(gHdc, 0, 0, rect.Width, rect.Height, dHdc, rect.X, rect.Y, TernaryRasterOperations.SRCCOPY);
            User32.ReleaseDC(deskHandle, dHdc);
            g.ReleaseHdc(gHdc);
            return bmp.Clone() as System.Drawing.Bitmap;
        }

        /// <summary>
        /// 获取给定图像的给定范围图像
        /// </summary>
        /// <param name="bitmap"></param>
        /// <param name="rectangle"></param>
        /// <returns></returns>
        public static System.Drawing.Bitmap? GetRectBitmap(System.Drawing.Bitmap bitmap, System.Drawing.Rectangle rectangle)
        {
            try
            {
                if (bitmap == null) return null;
                if (rectangle.Width == 0 || rectangle.Height == 0) return null;
                System.Drawing.Bitmap resultbitmap = new(rectangle.Width, rectangle.Height);
                using Graphics graphics = Graphics.FromImage(resultbitmap);
                System.Drawing.Rectangle rect1 = new System.Drawing.Rectangle(0, 0, rectangle.Width, rectangle.Height);
                graphics.DrawImage(bitmap, rect1, rectangle, GraphicsUnit.Pixel);
                return resultbitmap;
            }
            catch (Exception)
            {
                return null;
            }
        }
    }
}
